# -*- coding: utf8 -*-

from wsgiref.headers import Headers
from purest.web.util import format_as_http_date
from purest.web import status

class PlainResource(object):
    """ Provides a RESTful interface for WSGI. 

    Handler methods are named like the http verbs. 

    Example:

    class App1(PlainResource):
        def get(self, environ, start_response):
            start_response('200 Ok', [('Content-Type', 'text/plain')])
            return ['Hello World!']

        def last_modified(self, environ):
            return datetime.utcnow()
    """

    def __init__(self):
        """ Modify http_verbs if you want to use non-standard http methods. """
        self.http_verbs = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 
            'POST', 'PUT', 'TRACE']
        self._handlers = self._collect_handlers()
        self._allowed_methods = ', '.join(self._handlers)

    def _collect_handlers(self):
        handlers = {}
        for attribute in dir(self):
            attribute_name = attribute.upper()
            if attribute_name in self.http_verbs:
                handlers[attribute_name] = getattr(self, attribute)               
        return handlers
    
    def __call__(self, environ, start_response):
        """ Handles the request and dispatches it to the instance methods. """

        def start_response_wrapper(status, headers, exc_info=None):
            local_headers = Headers(headers)
            last_modified = self.last_modified(environ)
            if ('Last-Modified' not in local_headers and 
                    last_modified is not None):
                header = 'Last-Modified', format_as_http_date(last_modified)
                headers.append(header)
            return start_response(status, headers, exc_info)

        request_method = environ['REQUEST_METHOD']
        try:
            handler = self._handlers[request_method]            
        except KeyError:
            return self._send_method_not_allowed_status(start_response)
        return handler(environ, start_response_wrapper)

    def _send_method_not_allowed_status(self, start_response):
        headers = [('Allow', self._allowed_methods), 
            ('Content-Type', 'text/plain')]
        start_response(status.METHOD_NOT_ALLOWED, headers)
        return [status.METHOD_NOT_ALLOWED]

    def head(self, environ, start_response):
        """ Wraps a GET request and discards the body.

        Override this method to get a more efficient implementation without 
        generation of the body.

        Content-Length header may not work properly, because some WSGI runtimes 
        reset the value to '0' if there is no body.
        """
        if "GET" in self._handlers:
            self._handlers["GET"](environ, start_response)
            return []
        else:
            return self._send_method_not_allowed_status(start_response)

    def options(self, environ, start_response):
        """ responds with an http 'allow' header """
        headers = [('Allow', self._allowed_methods), ('Content-Length', '0')]
        start_response(status.OK, headers)
        return []

    def last_modified(self, environ):
        """ UTC date of the last modification of the requested resource or None.
        """
        return None

